<?php

namespace app\common\utils\upload\src\cos;
use app\service\JsonService;
use app\service\RedisService;
use Exception;
use Qcloud\Cos\Client;
use think\App;
use TencentCloud\Common\Exception\TencentCloudSDKException;
use QCloud\COSSTS\Sts;



class Cos extends Client
{

    public string $bucket = 'teaim-1259281518';

    protected App $app;
    protected Client $client;
    /**
     * 地域
     * @var string
     */
    protected string $region = "ap-nanjing";

    protected mixed $secretId;

    protected mixed $secretKey;

    protected string $scheme = 'https';

    public string $host = "https://teaim-1259281518.cos.ap-nanjing.myqcloud.com";


    /**
     * @var mixed
     */
    protected mixed $tmpSecretList;

    /**
     * @param App $app
     * @throws Exception
     */
    public function __construct(App $app)
    {
        $this->app = $app;
        $this->setSecretId(config('cloudstorage.storage.cos.secret_id'));
        $this->setSecretKey(config('cloudstorage.storage.cos.secret_key'));

        parent::__construct($this->cosConfig()); // TODO: Change the autogenerated stub


    }

    /**
     * @param mixed $secretId
     */
    public function setSecretId(mixed $secretId): void
    {
        $this->secretId = $secretId;
    }

    /**
     * @param mixed $secretKey
     */
    public function setSecretKey(mixed $secretKey): void
    {
        $this->secretKey = $secretKey;
    }

    /**
     * @return mixed
     */
    public function getSecretId(): mixed
    {
        return $this->secretId;
    }

    /**
     * @return mixed
     */
    public function getSecretKey(): mixed
    {
        return $this->secretKey;
    }

    /**
     * 设置地域
     * @param string $region
     */
    public function setRegion(string $region): void
    {
        $this->region = $region;
    }


    /**
     * 获取地域
     * @return string
     */
    public function getRegion(): string
    {
        return $this->region;
    }

    /**
     * 设置协议头部
     * @param string $scheme
     */
    public function setScheme(string $scheme): void
    {
        $this->scheme = $scheme;
    }

    /**
     * 获取协议头部
     * @return string
     */
    public function getScheme(): string
    {
        return $this->scheme;
    }

    /**
     * @return array
     * @throws Exception
     */
    public function cosConfig(): array
    {
        $this->getTmpSecretList();
        if ($this->tmpSecretList) {

          return [
              'region' => $this->region,
              'scheme' => $this->scheme, //协议头部，默认为http
              'signHost' => true, //默认签入Header Host；您也可以选择不签入Header Host，但可能导致请求失败或安全漏洞,若不签入host则填false
              'ServerSideEncryption' => 'AES256',	//SSE-COS加密
              'credentials'=> [
                  'secretId'  =>  $this->tmpSecretList['tmpSecretId'],
                  'secretKey' =>  $this->tmpSecretList['tmpSecretKey'],
                  'token'     =>  $this->tmpSecretList['tmpToken'],
              ]

          ];
        }

        return [];
    }

    /**
     * 获取临时秘钥
     * @return bool|string|array {
     * {
     * "Response": {
     * "Credentials": {
     * "Token": "kTRt***Jb7m",
     * "TmpSecretId": "AKID****CjE6",
     * "TmpSecretKey": "Eo28***7ps="
     * },
     * "Expiration": "2023-06-14T05:06:57Z",
     * "ExpiredTime": 1686719217,
     * "RequestId": "59a5e07e-4147-4d2e-a808-dca76ac5b3fd"
     * }
     * }
     * @throws Exception
     */
    public function setTmpPermissions(): bool|string|array
    {
        try {

            $config = array(
                'url' => 'https://sts.tencentcloudapi.com/', // url和domain保持一致
                'domain' => 'sts.tencentcloudapi.com', // 域名，非必须，默认为 sts.tencentcloudapi.com
                'proxy' => '',
                'secretId' => $this->getSecretId(), // 固定密钥,若为明文密钥，请直接以'xxx'形式填入，不要填写到getenv()函数中
                'secretKey' => $this->getSecretKey(), // 固定密钥,若为明文密钥，请直接以'xxx'形式填入，不要填写到getenv()函数中
                'bucket' =>$this->bucket, // 换成你的 bucket
                'region' => $this->region, // 换成 bucket 所在园区
                'durationSeconds' => 7200, // 密钥有效期
                'allowPrefix' => array('*'), // 这里改成允许的路径前缀，可以根据自己网站的用户登录态判断允许上传的具体路径，例子： a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
                // 密钥的权限列表。简单上传和分片需要以下的权限，其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
                'allowActions' => [
                    // 简单上传GetObjectUrl
                    'name/cos:*',
                ],
                // 临时密钥生效条件，关于condition的详细设置规则和COS支持的condition类型可以参考 https://cloud.tencent.com/document/product/436/71306
                "condition" => array(
                    "ip_equal" => array(
                        "qcs:ip" => array(
                            "129.204.195.239/24",

                        )
                    )
                )
            );

            // 获取临时密钥，计算签名
            $sts = $this->app->make(Sts::class);

            // 输出json格式的字符串回包
            $response = $sts->getTempKeys($config);

            if (isset($response['error'])) return false;

            // 设置缓存
            $redisService = $this->app->make(RedisService::class);
            $key = $redisService->getKey('cos','tmpToken');
            $info = [
                "tmpToken"     => $response['credentials']['sessionToken'],
                "tmpSecretId"  => $response['credentials']['tmpSecretId'],
                "tmpSecretKey" => $response['credentials']['tmpSecretKey'],
                "expiration"   => $response['expiration'],
                "expiredTime"  => $response['expiredTime'],
                "RequestId"    => $response['requestId']
            ];
            if ($redisService->set($key,$this->app->make(JsonService::class)->jsonEncode($info))) {
                $redisService->EXPIRE($key,$response['startTime']);
                $redisService->ttl($key);
            }

            return $info;
        }
        catch(TencentCloudSDKException $e) {
            return  $e->getMessage();
        }
    }

    /**
     * @return void
     * @throws Exception
     */
    public function getTmpSecretList(): void
    {

        $redisService = $this->app->make(RedisService::class);
        $key = $redisService->getKey('cos','tmpToken');
        $ttl = $redisService->ttl($key);
        if ($ttl > 300) {
            $response = $this->app->make(JsonService::class)->jsonDecode($redisService->get($key));

            $this->tmpSecretList = $response;

        } else {
            $this->tmpSecretList =  $this->setTmpPermissions();
        }



    }


}